#include <ptcParse.h>
#include <typeConvert.h>
#include <crcCalc.h>
static const uint8_t parseFixedHead[PTC_PACK_VER_PST] = {0X7A, 0XB5, 0X69}; // fixed head save
static void resetParseWork(struct ptcOptPsStruct *parseIstc)
{
    parseIstc->parseState = ptcPsStpFixHd;
    parseIstc->rcvCount = 0;
}

uint8_t ptcOptGetVersion(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    return parseIstc->pkptr[PTC_PACK_VER_PST];
}
int ptcOptSetVersion(void *ptcPtr, uint8_t setCrypte)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    return (parseIstc->pkptr[PTC_PACK_VER_PST] = setCrypte);
}

ptcPackType ptcOptGetHeadSize(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        return PTC_PACK_V1_DATA_PST;
        break;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return 0;
}
ptcPackType ptcOptGetDataSize(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        return ovtBigSys16(*((uint16_t *)(&parseIstc->pkptr[PTC_PACK_V1_SIZE_PST])));
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return 0;
}
int ptcOptSetDataSize(void *ptcPtr, ptcPackType setsize)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        uint16_t tmpSize = ovtBigSys16(setsize);
        memcpy(&parseIstc->pkptr[PTC_PACK_V1_SIZE_PST], &tmpSize, sizeof(setsize));
        return setsize;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
const uint8_t *ptcOptGet485Addr(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        return &parseIstc->pkptr[PTC_PACK_V1_ADDR_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return NULL;
}
int ptcOptSet485Addr(void *ptcPtr, const uint8_t *setAddr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        memcpy(&parseIstc->pkptr[PTC_PACK_V1_ADDR_PST], setAddr, PTC_PACK_V1_ADDR_SIZE);
        return PTC_PACK_V1_ADDR_SIZE;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

int ptcOptCheckAddr(void *ptcPtr, const uint8_t *myaddr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        if (memcmp(&parseIstc->pkptr[PTC_PACK_V1_ADDR_PST], myaddr, PTC_PACK_V1_ADDR_SIZE) == 0)
        {
            return 0;
        }
        break;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

uint8_t ptcOptGetCrypte(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        return parseIstc->pkptr[PTC_PACK_V1_ENCYPT_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
int ptcOptSetCrypte(void *ptcPtr, uint8_t setCrypte)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        parseIstc->pkptr[PTC_PACK_V1_ENCYPT_PST] = setCrypte;
        return 0;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

uint8_t *ptcOptGetUsrData(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        return &parseIstc->pkptr[PTC_PACK_V1_DATA_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return NULL;
}
int ptcOptSetUsrData(void *ptcPtr, const uint8_t *usrData, ptcPackType dsize)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    if (parseIstc->pksize - ptcOptGetHeadSize(parseIstc) < dsize)
    {
        logerror("[psize=%d,ver=%d]dsize=%d", parseIstc->pksize, parseIstc->myVersion, dsize);
        return -1;
    }
    memcpy(ptcOptGetUsrData(parseIstc), usrData, dsize);
    ptcOptSetDataSize(parseIstc, dsize);
    return dsize;
}

static ptcPackType ptcOptGetCrcU8(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        return parseIstc->pkptr[PTC_PACK_V1_CRC_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
static int ptcOptSetCrcU8(void *ptcPtr, ptcPackType setCrc)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        parseIstc->pkptr[PTC_PACK_V1_CRC_PST] = setCrc;
        return 0;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

ptcPackType ptcOptGetTotalSize(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    return ptcOptGetDataSize(parseIstc) + ptcOptGetHeadSize(parseIstc);
}
ptcPackType ptcOptGetRemainSize(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    return parseIstc->pksize - ptcOptGetHeadSize(parseIstc);
}

ptcPackType ptcOptFinPack(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        ptcOptSetCrcU8(parseIstc, calcHashCrc8(ptcOptGetUsrData(parseIstc), ptcOptGetDataSize(parseIstc)));
        break;
    }
    default:
    {
        logerror("");
        return 0;
    }
    }
    memcpy(&parseIstc->pkptr[0], parseFixedHead, sizeof(parseFixedHead));
    ptcOptSetVersion(parseIstc, parseIstc->myVersion);
    return ptcOptGetTotalSize(parseIstc);
}

static int ptcOptCheckCrc(void *ptcPtr)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->myVersion)
    {
    case ptcPsVers1:
    {
        uint8_t tmpcrc;
        tmpcrc = calcHashCrc8(ptcOptGetUsrData(parseIstc), ptcOptGetDataSize(parseIstc));
        if (tmpcrc == (uint8_t)ptcOptGetCrcU8(parseIstc))
        { // ok
            return 0;
        }
        logerror("%x:%x", tmpcrc, ptcOptGetCrcU8(parseIstc));
        return -1;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
int ptcOptInit(void *ptcPtr, ptcPackType setPackSize, uint8_t setver)
{
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    if (!(parseIstc))
    {
        logerror("");
        return -1;
    }
    parseIstc->myVersion = setver;
    if ((setPackSize < (ptcPsOptComSize + ptcOptGetHeadSize(parseIstc))))
    {
        logerror("");
        return -1;
    }
    parseIstc->pksize = setPackSize - ptcPsOptComSize;
    resetParseWork(parseIstc);
    return 0;
}
int ptcOptPsData(void *ptcPtr, uint8_t indata)
{
    int tmpflag = 0;
    struct ptcOptPsStruct *parseIstc = (struct ptcOptPsStruct *)ptcPtr;
    switch (parseIstc->parseState)
    {
    case ptcPsStpFixHd:
    {
        if (parseIstc->rcvCount < sizeof(parseFixedHead))
        {
            if (indata == parseFixedHead[parseIstc->rcvCount])
            {

                parseIstc->pkptr[parseIstc->rcvCount++] = indata;
            }
            else
            {
                parseIstc->rcvCount = 0;
                if (indata == parseFixedHead[parseIstc->rcvCount])
                {
                    parseIstc->pkptr[parseIstc->rcvCount++] = indata;
                }
            }
        }
        if (parseIstc->rcvCount >= sizeof(parseFixedHead))
        {
            parseIstc->parseState = ptcPsStpVers;
        }
        break;
    }
    case ptcPsStpVers:
    {
        parseIstc->pkptr[parseIstc->rcvCount++] = indata;
        if (!(ptcOptGetVersion(parseIstc) == parseIstc->myVersion))
        {
            logerror("parseVersion:%d!=%d", parseIstc->myVersion, ptcOptGetVersion(parseIstc));
            resetParseWork(parseIstc);
            break;
        }
        parseIstc->needSize = ptcOptGetHeadSize(parseIstc);
        if (!parseIstc->needSize)
        {
            logerror("parseVersion:%d", ptcOptGetHeadSize(parseIstc));
            resetParseWork(parseIstc);
            break;
        }
        parseIstc->parseState = ptcPsStpVerHd;
        break;
    }
    case ptcPsStpVerHd:
    {
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            parseIstc->pkptr[parseIstc->rcvCount++] = indata;
        }
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            break;
        }
        parseIstc->needSize = ptcOptGetTotalSize(parseIstc);
        if (!(parseIstc->needSize > ptcOptGetHeadSize(parseIstc) &&
              parseIstc->needSize <= parseIstc->pksize))
        {
            logerror("%u,%u", parseIstc->needSize, parseIstc->pksize);
            resetParseWork(parseIstc);
            break;
        }
        parseIstc->parseState = ptcPsStpData;
        break;
    }
    case ptcPsStpData:
    {
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            parseIstc->pkptr[parseIstc->rcvCount++] = indata;
        }
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            break;
        }
        if (ptcOptCheckCrc(parseIstc) < 0)
        {
            logerror("");
            resetParseWork(parseIstc);
            break;
        }
        // parse ok!
        // ptcPsOptCbk(parseIstc);
        tmpflag = 1;
    }
    default:
        resetParseWork(parseIstc);
        break;
    }
    return tmpflag;
}
